package cn.dduan.fool.design.pattern.behavior.interpret;

import java.util.Stack;

/**
 * 解释器模式
 * <p>
 * 优点：
 * 1、解释器是一个简单的语法分析工具，它最显著的优点就是扩展性，修改语法规则只需要修改相应的非终结符就可以了，若扩展语法，只需要增加非终结符类就可以了
 * 2、增加了新的解释表达式的方式
 * 3、易于实现文法
 * <p>
 * 缺点：
 * 1、解释器模式会引起类的膨胀，每个语法都需要产生一个非终结符表达式，语法规则比较复杂时，就可能产生大量的类文件，为维护带来非常多的麻烦
 * 2、效率低下，采用递归调用方法
 * <p>
 * 适用场景：
 * 1、有一个简单的语法规则，比如一个sql语句，如果我们需要根据sql语句进行rm转换，就可以使用解释器模式来对语句进行解释
 * 2、一些重复发生的问题，比如加减乘除四则运算，但是公式每次都不同，有时是a+b-c*d，有时是a*b+c-d，等等，公式千变万化，但是都是由加减乘除四个非终结符来连接的，这时我们就可以使用解释器模式
 *
 * @author dduan
 * @version 1.0
 * @date 2023/4/10
 */
public class InterpretPattern {
    public static void main(String[] args) {
        String statement = "3 * 2 * 4 / 6 % 5";

        Calculator calculator = new Calculator();

        calculator.build(statement);

        int result = calculator.compute();

        System.out.println(statement + " = " + result);
    }
}

/**
 * 抽象解释器 ：AbstractExpression
 *
 * @author dduan
 * @version 1.0
 * @date 2023/4/10
 */
interface Node {
    public int interpret();
}

/**
 * 非终结符表达式：NonterminalExpression
 *
 * @author dduan
 * @version 1.0
 * @date 2023/4/10
 */
class ValueNode implements Node {
    private int value;

    public ValueNode(int value) {
        this.value = value;
    }

    @Override
    public int interpret() {
        return this.value;
    }
}

/**
 * 终结表达式抽象类
 *
 * @author dduan
 * @version 1.0
 * @date 2023/4/10
 */
abstract class SymbolNode implements Node {
    protected Node left;
    protected Node right;

    public SymbolNode(Node left, Node right) {
        this.left = left;
        this.right = right;
    }
}

/**
 * 具体终结表达式：乘
 *
 * @author dduan
 * @version 1.0
 * @date 2023/4/10
 */
class MulNode extends SymbolNode {
    public MulNode(Node left, Node right) {
        super(left, right);
    }

    @Override
    public int interpret() {
        return left.interpret() * right.interpret();
    }
}

/**
 * 具体终结表达式：求模
 *
 * @author dduan
 * @version 1.0
 * @date 2023/4/10
 */
class ModNode extends SymbolNode {
    public ModNode(Node left, Node right) {
        super(left, right);
    }

    @Override
    public int interpret() {
        return super.left.interpret() % super.right.interpret();
    }
}

/**
 * 具体终结表达式：除
 *
 * @author dduan
 * @version 1.0
 * @date 2023/4/10
 */
class DivNode extends SymbolNode {
    public DivNode(Node left, Node right) {
        super(left, right);
    }

    @Override
    public int interpret() {
        return super.left.interpret() / super.right.interpret();
    }
}

/**
 * 计算器：环境类
 *
 * @author dduan
 * @version 1.0
 * @date 2023/4/10
 */
class Calculator {
    private String statement;
    private Node node;

    public void build(String statement) {
        Node left = null, right = null;
        Stack stack = new Stack();

        String[] statementArr = statement.split(" ");

        for (int i = 0; i < statementArr.length; i++) {
            if ("*".equalsIgnoreCase(statementArr[i])) {
                left = (Node) stack.pop();
                int val = Integer.parseInt(statementArr[++i]);
                right = new ValueNode(val);
                stack.push(new MulNode(left, right));
            } else if ("/".equalsIgnoreCase(statementArr[i])) {
                left = (Node) stack.pop();
                int val = Integer.parseInt(statementArr[++i]);
                right = new ValueNode(val);
                stack.push(new DivNode(left, right));
            } else if ("%".equalsIgnoreCase(statementArr[i])) {
                left = (Node) stack.pop();
                int val = Integer.parseInt(statementArr[++i]);
                right = new ValueNode(val);
                stack.push(new ModNode(left, right));
            } else {
                stack.push(new ValueNode(Integer.parseInt(statementArr[i])));
            }
        }
        this.node = (Node) stack.pop();
    }

    public int compute() {
        return node.interpret();
    }
}